package com.dhcc.utils.object;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;

import com.dhcc.utils.__Convert;
import com.dhcc.utils.__Object.Options;

public class ObjectCopierProxy extends BaseObjectCopier implements InvocationHandler{
	
//	private Object target;
//	private Object source;
	private Invoker[] getFields;
	private Invoker[] setFields;
	public ObjectCopierProxy(Object target, Object source, String field, int option) {
		this.targetType = target.getClass();
		this.sourceType = source.getClass();
		this.fields = field;
		this.option = option;
//		this.target = target;
//		this.source = source;
		try{
			parse(field);
		}catch(Exception ex){
			throw new RuntimeException("解析 "+field+" 出错, 确认target set 以及 source get 方法正常", ex);
		}
	}
	private void parse(String field) throws Exception {
		String[] strs = field.split(",");
		Invoker[] gets = new Invoker[strs.length];
		Invoker[] sets = new Invoker[strs.length];
		for (int i = 0; i < strs.length; i++) {
			String str = strs[i];
			int index = str.indexOf(':');
			String left;
			String right;
			if(index>0){
				left = str.substring(0, index).trim();
				right = str.substring(index+1).trim();
			}else{
				left = str.trim();
				right = str.trim();
			}
			gets[i] = getInvoker(this.sourceType, right, 0);
			sets[i] = getInvoker(this.targetType, left, 1);
		}
		getFields = gets;
		setFields = sets;
	}
	/**
	 * 
	 * @param type
	 * @param field
	 * @param readOrWrite 0 read, 1 write
	 * @return
	 */
	private Invoker getInvoker(Class type, String field, int rw){
		int index = field.indexOf(".");
		if(index>=0){
			String head = field.substring(0, index);
			String tail =  field.substring(index+1);
			Invoker cur = getInvoker(type, head, 0);
			Invoker next = getInvoker(cur.getReturnType(), tail, rw);
			return new ChainInvoker(cur, next);
		}
		char[] chars = field.toCharArray();
		chars[0] = Character.toUpperCase(chars[0]);
		String cap = new String(chars);
		try{
			PropertyDescriptor pd = new PropertyDescriptor(field, type, rw==0? "is"+cap:null, rw==1?"set"+cap:null);
			return new PojoInvoker(rw==0? pd.getReadMethod():pd.getWriteMethod());
		}catch(IntrospectionException ex){
		    if(Map.class.isAssignableFrom(type)){
		    	return new MapInvoker(field);
		    }
		}
		throw new RuntimeException("cannot "+(rw==0?"get":"set")+" "+field+" in "+type.getName());
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		if("copy".equals(method.getName())){
			for (int i = 0; i < getFields.length; i++) {
				Object value = getFields[i].invokeGet(args[1]);
				if(copyCheck(value, option)){
					value = __Convert.changeType(value, setFields[i].getParameterType());
					setFields[i].invokeSet(args[0], value);
				}
			}
			return null;
		}else if("support".equals(method.getName())){
			return this.support(args[0], args[1], (String)args[2], (Integer)args[3]);
		}else{
			return method.invoke(proxy, args);
		}
	}
	
	/**
	 * 检查是否需要复制属性
	 * @param value
	 * @param option
	 * @return
	 */
	private boolean copyCheck(Object value, int option) {
		if(option==Options.ALL){
			return true;
		}
		if(value==null && (option&Options.NOT_NULL)==Options.NOT_NULL){
			return false;
		}
		return true;
	}
}